# -*- coding: mbcs -*-
from part import *
from material import *
from section import *
from assembly import *
from step import *
from interaction import *
from load import *
from mesh import *
from optimization import *
from job import *
from sketch import *
from visualization import *
from connectorBehavior import *

class RotatingRectangle():

  def __init__(self, A, B, X_N, Y_N, YOUNGS_MODULUS, POISSONS_RATIO, THICKNESS):

    self.A = A       # 矩形长度
    self.B = B       # 矩形宽度

    self.X_N = X_N   # x轴阵列个数
    self.Y_N = Y_N   # y轴阵列个数

    self.X_SPACE = A  # x轴阵列间距
    self.Y_SPACE = B  # y轴阵列间距

    self.YOUNGS_MODULUS = YOUNGS_MODULUS  # 杨氏模量
    self.POISSONS_RATIO = POISSONS_RATIO  # 泊松比
    self.THICKNESS = THICKNESS            # 矩形厚度

  # 生成矩形胞元顶点
  def generateCellUnit(self):

    A = self.A
    B = self.B

    point_1 = (0, 0)
    point_2 = (0, B)
    point_3 = (A, B)
    point_4 = (A, 0)

    points = [point_1, point_2, point_3, point_4]

    return points

  # 移动点
  def move(self, offset_x, offset_y, points):

    res = []

    for point in points:
      movedPoint = (point[0] + offset_x, point[1] + offset_y)
      res.append(movedPoint)

    return res

  # 创建part
  def createPart(self, points, partName):

    mdb.models['Model-1'].ConstrainedSketch(name='__profile__', sheetSize=200.0)
    mdb.models['Model-1'].sketches['__profile__'].Line(point1=points[0], point2=points[1])
    mdb.models['Model-1'].sketches['__profile__'].Line(point1=points[1], point2=points[2])
    mdb.models['Model-1'].sketches['__profile__'].Line(point1=points[2], point2=points[3])
    mdb.models['Model-1'].sketches['__profile__'].Line(point1=points[3], point2=points[0])

    mdb.models['Model-1'].Part(dimensionality=THREE_D, name=partName, type=
        DEFORMABLE_BODY)
    mdb.models['Model-1'].parts[partName].BaseShell(sketch=
        mdb.models['Model-1'].sketches['__profile__'])
    del mdb.models['Model-1'].sketches['__profile__']

  # 阵列part
  def arrayPart(self):

    X_N = self.X_N
    Y_N = self.Y_N

    X_SPACE = self.X_SPACE
    Y_SPACE = self.Y_SPACE

    cellUnitPoints = self.generateCellUnit()

    for i in range(Y_N):

      for j in range(X_N):

        partName = "Part-" + str(i+1) + '-' + str(j+1)

        points = self.move(X_SPACE * j, Y_SPACE * i, cellUnitPoints)

        self.createPart(points, partName)

  # 装配part
  def assembly(self):

    mdb.models['Model-1'].rootAssembly.DatumCsysByDefault(CARTESIAN)

    X_N = self.X_N
    Y_N = self.Y_N

    for i in range(Y_N):

      for j in range(X_N):

        partName = "Part-" + str(i+1) + '-' + str(j+1)

        mdb.models['Model-1'].rootAssembly.Instance(dependent=ON, name=partName + '-1', 
          part=mdb.models['Model-1'].parts[partName])

  # 添加转动副
  def addHinge(self, partName_1, num_1, partName_2, num_2, count):

    mdb.models['Model-1'].rootAssembly.DatumCsysByThreePoints(coordSysType=
      CARTESIAN, line1=(1.0, 0.0, 0.0), line2=(0.0, 1.0, 0.0), origin=
      mdb.models['Model-1'].rootAssembly.instances['Part-1-1-1'].vertices[1])
    mdb.models['Model-1'].rootAssembly.WirePolyLine(mergeType=IMPRINT, meshable=
        False, points=((
        mdb.models['Model-1'].rootAssembly.instances[partName_1].vertices[num_1], 
        mdb.models['Model-1'].rootAssembly.instances[partName_2].vertices[num_2]), ))
    mdb.models['Model-1'].rootAssembly.features.changeKey(fromName='Wire-' + str(count+1), 
        toName='Wire-' + str(count+1))
    mdb.models['Model-1'].rootAssembly.Set(edges=
        mdb.models['Model-1'].rootAssembly.edges.getSequenceFromMask(('[#1 ]', ), )
        , name='Wire-' + str(count+1) + '-Set-1')
    mdb.models['Model-1'].rootAssembly.SectionAssignment(region=
        mdb.models['Model-1'].rootAssembly.sets['Wire-' + str(count+1) + '-Set-1'], sectionName=
        'ConnSect-Hinge')
    mdb.models['Model-1'].rootAssembly.sectionAssignments[count].getSet()
    keys = mdb.models['Model-1'].rootAssembly.datums.keys()
    mdb.models['Model-1'].rootAssembly.ConnectorOrientation(localCsys1=
        mdb.models['Model-1'].rootAssembly.datums[keys[-1]], region=
        mdb.models['Model-1'].rootAssembly.allSets['Wire-' + str(count+1) + '-Set-1'])
  
  # 批量添加转动副
  def arrayHinge(self):

    mdb.models['Model-1'].ConnectorSection(assembledType=HINGE, name='ConnSect-Hinge')

    X_N = self.X_N
    Y_N = self.Y_N

    # 转动副添加计数
    count = 0

    # 第y行矩形之间的转动副
    for y in range(Y_N):

      # 奇数行
      if(y % 2 == 0):
        
        # 奇数行下方的转动副
        for i in range(X_N // 2):
          partName_1 = 'Part-' + str(y+1) + '-' + str(2*i+1) + '-1'
          partName_2 = 'Part-' + str(y+1) + '-' + str(2*i+2) + '-1'
          self.addHinge(partName_1, 1, partName_2, 0, count)
          count += 1
        
        # 奇数行，偶数列时，上方的转动副
        if(X_N % 2 == 0):
          for m in range(X_N // 2 - 1):
            partName_1 = 'Part-' + str(y+1) + '-' + str(2*m+2) + '-1'
            partName_2 = 'Part-' + str(y+1) + '-' + str(2*m+3) + '-1'
            self.addHinge(partName_1, 2, partName_2, 3, count)
            count += 1
        
        # 奇数行，奇数列时，上方的转动副
        if(X_N % 2 == 1):
          for n in range(X_N // 2):
            partName_1 = 'Part-' + str(y+1) + '-' + str(2*n+2) + '-1'
            partName_2 = 'Part-' + str(y+1) + '-' + str(2*n+3) + '-1'
            self.addHinge(partName_1, 2, partName_2, 3, count)
            count += 1

      # 偶数行
      if(y % 2 == 1):
        
        # 偶数行上方的转动副
        for j in range(X_N // 2):
          partName_1 = 'Part-' + str(y+1) + '-' + str(2*j+1) + '-1'
          partName_2 = 'Part-' + str(y+1) + '-' + str(2*j+2) + '-1'
          self.addHinge(partName_1, 2, partName_2, 3, count)
          count += 1
        
        # 偶数行，奇数列时，下方的转动副
        if(X_N % 2 == 0):
          for a in range(X_N // 2 - 1):
            partName_1 = 'Part-' + str(y+1) + '-' + str(2*a+2) + '-1'
            partName_2 = 'Part-' + str(y+1) + '-' + str(2*a+3) + '-1'
            self.addHinge(partName_1, 1, partName_2, 0, count)
            count += 1
        
        # 偶数行，偶数列时，下方的转动副
        if(X_N % 2 == 1):
          for b in range(X_N // 2):
            partName_1 = 'Part-' + str(y+1) + '-' + str(2*b+2) + '-1'
            partName_2 = 'Part-' + str(y+1) + '-' + str(2*b+3) + '-1'
            self.addHinge(partName_1, 1, partName_2, 0, count)
            count += 1
    
    # 第x列矩形之间的转动副
    for x in range(X_N):

      # 奇数列
      if(x % 2 == 0):
        
        # 奇数列右边的转动副
        for c in range(Y_N // 2):
          partName_1 = 'Part-' + str(2*c+1) + '-' + str(x+1) + '-1'
          partName_2 = 'Part-' + str(2*c+2) + '-' + str(x+1) + '-1'
          self.addHinge(partName_1, 2, partName_2, 1, count)
          count += 1
        
        # 奇数列，偶数行时，左边的转动副
        if(Y_N % 2 == 0):
          for d in range(Y_N // 2 - 1):
            partName_1 = 'Part-' + str(2*d+2) + '-' + str(x+1) + '-1'
            partName_2 = 'Part-' + str(2*d+3) + '-' + str(x+1) + '-1'
            self.addHinge(partName_1, 3, partName_2, 0, count)
            count += 1
        
        # 奇数列，奇数行时，左边的转动副
        if(Y_N % 2 == 1):
          for e in range(Y_N // 2):
            partName_1 = 'Part-' + str(2*e+2) + '-' + str(x+1) + '-1'
            partName_2 = 'Part-' + str(2*e+3) + '-' + str(x+1) + '-1'
            self.addHinge(partName_1, 3, partName_2, 0, count)
            count += 1

      # 偶数列
      if(x % 2 == 1):
        
        # 偶数列左边的转动副
        for f in range(Y_N // 2):
          partName_1 = 'Part-' + str(2*f+1) + '-' + str(x+1) + '-1'
          partName_2 = 'Part-' + str(2*f+2) + '-' + str(x+1) + '-1'
          self.addHinge(partName_1, 3, partName_2, 0, count)
          count += 1
        
        # 偶数列，奇数行时，右边的转动副
        if(Y_N % 2 == 0):
          for g in range(X_N // 2 - 1):
            partName_1 = 'Part-' + str(2*g+2) + '-' + str(x+1) + '-1'
            partName_2 = 'Part-' + str(2*g+3) + '-' + str(x+1) + '-1'
            self.addHinge(partName_1, 2, partName_2, 1, count)
            count += 1
        
        # 偶数列，偶数行时，右边的转动副
        if(Y_N % 2 == 1):
          for h in range(X_N // 2):
            partName_1 = 'Part-' + str(2*h+2) + '-' + str(x+1) + '-1'
            partName_2 = 'Part-' + str(2*h+3) + '-' + str(x+1) + '-1'
            self.addHinge(partName_1, 2, partName_2, 1, count)
            count += 1

    print('Hinge num: %d' % count)

  # 设置材料属性
  def setMaterial(self):

    YOUNGS_MODULUS = self.YOUNGS_MODULUS
    POISSONS_RATIO = self.POISSONS_RATIO
    THICKNESS =  self.THICKNESS

    mdb.models['Model-1'].Material(name='Material-1')
    mdb.models['Model-1'].materials['Material-1'].Elastic(table=((YOUNGS_MODULUS, POISSONS_RATIO), 
      ))
    mdb.models['Model-1'].HomogeneousShellSection(idealization=NO_IDEALIZATION, 
      integrationRule=SIMPSON, material='Material-1', name='Section-1', 
      numIntPts=5, poissonDefinition=DEFAULT, preIntegrate=OFF, temperature=
      GRADIENT, thickness=THICKNESS, thicknessField='', thicknessModulus=None, 
      thicknessType=UNIFORM, useDensity=OFF)

  # 赋予各个part材料属性
  def assignMaterial(self):

    X_N = self.X_N
    Y_N = self.Y_N

    for i in range(Y_N):
      for j in range(X_N):
        partName = "Part-" + str(i+1) + '-' + str(j+1)
        mdb.models['Model-1'].parts[partName].SectionAssignment(offset=0.0, 
          offsetField='', offsetType=MIDDLE_SURFACE, region=Region(
          faces=mdb.models['Model-1'].parts[partName].faces.getSequenceFromMask(
          mask=('[#1 ]', ), )), sectionName='Section-1', thicknessAssignment=
          FROM_SECTION)

  # 为所有part划分网格
  def mesh(self):

    X_N = self.X_N
    Y_N = self.Y_N

    for i in range(Y_N):
      for j in range(X_N):
        partName = "Part-" + str(i+1) + '-' + str(j+1)
        mdb.models['Model-1'].parts[partName].seedPart(deviationFactor=0.1, 
            minSizeFactor=0.1, size=1.0)
        mdb.models['Model-1'].parts[partName].generateMesh()

  # 创建分析步，固定步长0.02，共50帧
  def step(self):
    mdb.models['Model-1'].StaticStep(initialInc=0.02, name='Step-1', nlgeom=ON, 
      noStop=OFF, previous='Initial', timeIncrementationMethod=AUTOMATIC)

  # 添加边界条件
  def load(self):

    X_N = self.X_N
    Y_N = self.Y_N

    mdb.models['Model-1'].DisplacementBC(amplitude=UNSET, createStepName='Initial', 
      distributionType=UNIFORM, fieldName='', localCsys=None, name='BC-1', 
      region=Region(
      vertices=mdb.models['Model-1'].rootAssembly.instances['Part-1-1-1'].vertices.getSequenceFromMask(
      mask=('[#1 ]', ), )), u1=SET, u2=SET, u3=SET, ur1=SET, ur2=SET, ur3=UNSET)

    partName = 'Part-' + str(X_N) + '-' + str(Y_N) + '-1'
    mdb.models['Model-1'].ConcentratedForce(cf1=1000.0, cf2=1000.0, createStepName=
      'Step-1', distributionType=UNIFORM, field='', localCsys=None, name='Load-1'
      , region=Region(
      vertices=mdb.models['Model-1'].rootAssembly.instances[partName].vertices.getSequenceFromMask(
      mask=('[#4 ]', ), )))
  
  # 创建作业
  def job(self):
    mdb.Job(atTime=None, contactPrint=OFF, description='', echoPrint=OFF, 
      explicitPrecision=SINGLE, getMemoryFromAnalysis=True, historyPrint=OFF, 
      memory=90, memoryUnits=PERCENTAGE, model='Model-1', modelPrint=OFF, 
      multiprocessingMode=DEFAULT, name='Job-1', nodalOutputPrecision=SINGLE, 
      numCpus=1, numGPUs=0, queue=None, resultsFormat=ODB, scratch='', type=
      ANALYSIS, userSubroutine='', waitHours=0, waitMinutes=0)
  
  def printParameters(self):

    print(" ")
    # 打印参数
    print("A: %s " % self.A)
    print("B: %s " % self.B)
    print("X_N: %d " % self.X_N)
    print("Y_N: %d " % self.Y_N)

def main(A, B, X_N, Y_N, YOUNGS_MODULUS, POISSONS_RATIO, THICKNESS):
  rotatingRectangle = RotatingRectangle(A, B, X_N, Y_N, YOUNGS_MODULUS, POISSONS_RATIO, THICKNESS)

  rotatingRectangle.arrayPart()
  rotatingRectangle.assembly()
  rotatingRectangle.arrayHinge()
  rotatingRectangle.setMaterial()
  rotatingRectangle.assignMaterial()
  rotatingRectangle.mesh()
  rotatingRectangle.step()
  rotatingRectangle.load()
  rotatingRectangle.job()
  rotatingRectangle.printParameters()

if __name__ == '__main__':

  main(A=10.0, B=10.0, X_N=5, Y_N=5, 
       YOUNGS_MODULUS=210000, 
       POISSONS_RATIO=0.3,
       THICKNESS=1)

# Save by cgp on 2021_11_25-17.25.55; build 6.14-5 2015_08_18-22.37.49 135153
